import 'webrtc-adapter';
import { HubConnectionBuilder } from '@microsoft/signalr';

// 通用建立信令过程类
class MyWebRTC {
  peerConns = {}; //所有对等端{[name]:pc}
  connection = null;
  me = null;
  wsUrl;
  dataCallBack;
  streamCallBack;

  constructor(url, onData, onStream) {
    this.dataCallBack = onData;
    this.streamCallBack = onStream;
    this.wsUrl = url;
  }

  async setupSignalR() {
    const ws = new HubConnectionBuilder()
      .withUrl(this.wsUrl)
      .withAutomaticReconnect()
      .build();

    ws.on('onLogin', (name) => {
      console.log(name, '登录系统');
      this.me = name;
    });

    ws.on('onOffer', async (user, offer) => {
      if (user && offer) {
        console.log(user, '邀请', this.me);
        // 应答他人需要新的点对点连接
        const pc = this.createPC(user);
        await pc.setRemoteDescription(new RTCSessionDescription(offer));
        // 此时开启本地流媒体，注意顺序
        await this.responseChannel(pc, user);

        const answer = await pc.createAnswer();
        await pc.setLocalDescription(answer);
        // 应答他人
        await this.connection.invoke('Answer', user, answer);
      }
    });

    ws.on('onAnswer', async (user, answer) => {
      console.log(user, '应答', this.me);
      const pc = this.peerConns[user];
      if (pc && answer) {
        // 保存远程应答会话
        await pc.setRemoteDescription(new RTCSessionDescription(answer));
      }
    });

    ws.on('onCandidate', async (user, candidate) => {
      console.log(user, '发送候选信息给', this.me, candidate);
      const pc = this.peerConns[user];
      if (pc) {
        await pc.addIceCandidate(new RTCIceCandidate(candidate));
      }
    });

    ws.on('onLeave', (user) => {
      // 对等端离线
      this.handleLeave(user);
    });

    await ws.start();

    this.connection = ws;
  }

  // 抽象方法，具体由继承类实现.创建数据通道
  requestChannel(pc) {}
  responseChannel(pc) {}

  // 创建与他人点对点连接
  createPC = (name) => {
    if (!RTCPeerConnection) {
      alert('浏览器不支持webrtc');
      return;
    }
    const iceConfig = {
      iceServers: [{ urls: 'stun:stun2.1.google.com:19302' }],
    };
    const pc = new RTCPeerConnection(iceConfig);
    //ICE候选发送到远程对等方,只要本地代理ICE需要通过信令服务器传递信息给其他对等端时就会触发
    //createOffer或createAnswer生成的SDP调用setLocalDescription，ICE采集就会开始
    pc.onicecandidate = (event) => {
      if (event.candidate) {
        this.connection.invoke('Candidate', name, event.candidate);
      }
    };
    // 监听对等端流媒体
    pc.ontrack = (e) => {
      if (e && e.streams) {
        // 对方流回调
        this.streamCallBack(name, e.streams[0]);
      }
    };
    // 该连接针对的对象名
    pc.myname = name;
    this.peerConns[name] = pc;
    return pc;
  };

  // 处理我对某人的连接断开
  handleLeave = (name) => {
    const pc = this.peerConns[name];
    if (pc) {
      // 关闭本地数据通道
      if (pc.channel) {
        pc.channel.close();
      }

      // 关闭本人对于他人的连接
      pc.close();
      delete this.peerConns[name];
    }
  };

  //个人加入
  login = async (name) => {
    if (name) {
      await this.connection.invoke('Login', name);
    }
  };

  // 呼叫他人
  call = async (name) => {
    const pc = this.createPC(name);
    await this.requestChannel(pc, name);
    // 数据通道打开以后创建请求
    const offer = await pc.createOffer();
    await pc.setLocalDescription(offer);
    await this.connection.invoke('Offer', name, offer);
  };

  // 本人下线并通知他人
  leave = (name) => {
    this.connection.invoke('Leave', name);
    // 本地流存在则停止
    if (this.localStream) {
      this.localStream.getTracks().forEach((track) => {
        track.stop();
      });
    }
    this.handleLeave(name);
  };

  // 释放
  dispose = () => {
    this.me = null;
    // 遍历所有的点对点连接并关闭
    _.forEach(this.peerConns, async (pc) => {
      this.leave(pc.myname);
    });
    if (this.connection) {
      this.connection.stop();
      this.connection = null;
    }
    this.peerConns = null;
  };
}
export default MyWebRTC;
